/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.revivius.jbtorrent.parse;

import com.revivius.jbtorrent.entity.Torrent;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 *
 * @author Revivius
 */
public class TorrentParser {

    private static final Logger LOG = Logger.getLogger(TorrentParser.class.getName());
    
    private static final String ANNOUNCE = "announce";
    private static final String ANNOUNCE_LIST = "announce-list";
    private static final String COMMENT = "comment";
    private static final String CREATED_BY = "created by";
    private static final String CREATION_DATE = "creation date";
    private static final String INFO = "info";

    private static final Map<String, KeyParser> PARSERS = new HashMap<>();
    static {
        PARSERS.put(ANNOUNCE, new AnnounceParser());
        PARSERS.put(ANNOUNCE_LIST, new AnnounceListParser());
        PARSERS.put(COMMENT, new CommentParser());
        PARSERS.put(CREATED_BY, new CreatedByParser());
        PARSERS.put(CREATION_DATE, new CreationDateParser());
        PARSERS.put(INFO, new InfoParser());
    }
    
    private TorrentParser() { }
    
    public static Torrent parse(Map<String, Object> map) {
        
        Torrent torrent = new Torrent();
        
        map.entrySet().stream().forEach(e -> {
                    parseKey(e, torrent);
                });
        
        return torrent;
    }

    private static void parseKey(Map.Entry<String, Object> entry, Torrent torrent) {
        String key = entry.getKey();
        Object value = entry.getValue();

        KeyParser parser = PARSERS.get(key);
        if (parser == null) {
            LOG.log(Level.WARNING, "Unknown key: {0}, value is: {1}", new Object[]{key, value});
            torrent.addSkipped(key, value);
        } else {
            try {
                parser.parse(key, value, torrent);
            } catch (Exception ex) {
                LOG.log(Level.SEVERE, "Can not parse value of : " + key, ex);
                torrent.addSkipped(key, value);
            }
        }
    }


    private static class AnnounceParser implements KeyParser {

        @Override
        public void parse(String key, Object value, Torrent torrent) throws Exception {
            torrent.setAnnounce(KeyParser.fromByteArray(value));
        }

    }

    private static class AnnounceListParser implements KeyParser {

        @Override
        public void parse(String key, Object value, Torrent torrent) throws Exception {

            List<List<byte[]>> list = (List<List<byte[]>>) value;

            List<String> strList = list.stream()
                    .map(KeyParser::fromList)
                    .collect(Collectors.toList());

            torrent.setAnnounceList(new ArrayList<>(strList));
        }

    }

    private static class CommentParser implements KeyParser {

        @Override
        public void parse(String key, Object value, Torrent torrent) throws Exception {
            torrent.setComment(KeyParser.fromByteArray(value));
        }

    }

    private static class CreatedByParser implements KeyParser {

        @Override
        public void parse(String key, Object value, Torrent torrent) throws Exception {
            torrent.setCreatedBy(KeyParser.fromByteArray(value));
        }

    }

    private static class CreationDateParser implements KeyParser {

        @Override
        public void parse(String key, Object value, Torrent torrent) throws Exception {
            BigInteger bi = (BigInteger) value;

            torrent.setCreationDate(new Date(bi.longValueExact()));
        }

    }


}
